home *** CD-ROM | disk | FTP | other *** search
- /* Simple 'n' stupid dynamic-array module.
- Copyright (C) 1993 Sun Microsystems, Inc.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: Not in FSF. */
-
- /* Written by Ben Wing, December 1993. */
-
- /*
-
- A "dynamic array" is a contiguous array of fixed-size elements where there
- is no upper limit (except available memory) on the number of elements in the
- array. Because the elements are maintained contiguously, space is used
- efficiently (no per-element pointers necessary) and random access to a
- particular element is in constant time. At any one point, the block of memory
- that holds the array has an upper limit; if this limit is exceeded, the
- memory is realloc()ed into a new array that is twice as big. Assuming that
- the time to grow the array is on the order of the new size of the array
- block, this scheme has a provably constant amortized time (i.e. average
- time over all additions).
-
- When you add elements or retrieve elements, pointers are used. Note that
- the element itself (of whatever size it is), and not the pointer to it,
- is stored in the array; thus you do not have to allocate any heap memory
- on your own. Also, returned pointers are only guaranteed to be valid
- until the next operation that changes the length of the array.
-
- This is a container object. Declare a dynamic array of a specific type
- as follows:
-
- struct mytype_dynarr
- {
- Dynarr_declare (mytype);
- };
-
- Use the following functions/macros:
-
- void *Dynarr_new(type)
- [MACRO] Create a new dynamic-array object, with each element of the
- specified type. The return value is a void * and must be cast to the
- proper dynamic array type.
- Dynarr_add(d, el)
- [MACRO] Add an element to the end of a dynamic array. EL is a pointer
- to the element; the element itself is stored in the array, however.
- No function call is performed unless the array needs to be resized.
- Dynarr_add_many(d, base, len)
- [MACRO] Add LEN elements to the end of the dynamic array. The elements
- should be contiguous in memory, starting at BASE.
- Dynarr_insert_many_at_start(d, base, len)
- [MACRO] Append LEN elements to the beginning of the dynamic array.
- The elements should be contiguous in memory, starting at BASE.
- Dynarr_insert_many(d, base, len, start)
- Insert LEN elements to the dynamic arrary starting at position
- START. The elements should be contiguous in memory, starting at BASE.
- int Dynarr_length(d)
- [MACRO] Return the number of elements currently in a dynamic array.
- type Dynarr_at(d, i)
- [MACRO] Return the element at the specified index (no bounds checking
- done on the index). The element itself is returned, not a pointer
- to it.
- type *Dynarr_atp(d, i)
- [MACRO] Return a pointer to the element at the specified index (no
- bounds checking done on the index). The pointer may not be valid
- after an element is added to or removed from the array.
- Dynarr_reset(d)
- [MACRO] Reset the length of a dynamic array to 0.
- Dynarr_free(d)
- Destroy a dynamic array and the memory allocated to it.
-
- Use the following global variable:
-
- Dynarr_min_size
- Minimum allowable size for a dynamic array when it is resized. The
- default is 32 and does not normally need to be changed.
-
- */
-
- #include <config.h>
- #include "lisp.h"
-
- int Dynarr_min_size = 1;
-
- void *
- Dynarr_newf (int elsize)
- {
- Dynarr *d = (Dynarr *) xmalloc (sizeof (Dynarr));
-
- memset (d, 0, sizeof (*d));
- d->elsize = elsize;
-
- return d;
- }
-
- void
- Dynarr_resize (void *d, int size)
- {
- int newsize;
- double multiplier;
- Dynarr *dy = (Dynarr *) d;
-
- if (dy->max <= 8)
- multiplier = 2;
- else
- multiplier = 1.5;
-
- for (newsize = dy->max; newsize < size;)
- newsize = max (Dynarr_min_size, multiplier * newsize);
-
- /* Don't do anything if the array is already big enough. */
- if (newsize > dy->max)
- {
- dy->base = xrealloc (dy->base, newsize*dy->elsize);
- dy->max = newsize;
- }
- }
-
- /* Add a number of contiguous elements to the array starting at START. */
- void
- Dynarr_insert_many (void *d, void *el, int len, int start)
- {
- Dynarr *dy = (Dynarr *) d;
-
- Dynarr_resize (dy, dy->cur+len);
- /* Silently adjust start to be valid. */
- if (start > dy->cur)
- start = dy->cur;
- else if (start < 0)
- start = 0;
-
- if (start != dy->cur)
- {
- memmove ((char *) dy->base + (start + len)*dy->elsize,
- (char *) dy->base + start*dy->elsize,
- (dy->cur - start)*dy->elsize);
- }
- memcpy ((char *) dy->base + start*dy->elsize, el, len*dy->elsize);
- dy->cur += len;
-
- if (dy->cur > dy->largest)
- dy->largest = dy->cur;
- }
-
- void
- Dynarr_delete_many (void *d, int start, int len)
- {
- Dynarr *dy = (Dynarr *) d;
-
- assert (start >= 0 && len >= 0 && start + len <= dy->cur);
- memmove ((char *) dy->base + start*dy->elsize,
- (char *) dy->base + (start + len)*dy->elsize,
- (dy->cur - start - len)*dy->elsize);
- dy->cur -= len;
- }
-
- void
- Dynarr_free (void *d)
- {
- Dynarr *dy = (Dynarr *) d;
-
- if (dy->base)
- xfree (dy->base);
- xfree (dy);
- }
-